// @Author EthanScriptOn
// @Desc
package component

import (
	"fmt"
	"gitee.com/fatzeng/srf_switch_dynamic_logic_director/common"
	"github.com/golang-jwt/jwt/v4"
	"time"
)

type JwtSigningMethod = string

const (
	HS256 JwtSigningMethod = "HS256"
	HS384 JwtSigningMethod = "HS384"
	HS512 JwtSigningMethod = "HS512"
	RS256 JwtSigningMethod = "RS256"
	RS384 JwtSigningMethod = "RS384"
	RS512 JwtSigningMethod = "RS512"
	ES256 JwtSigningMethod = "ES256"
	ES384 JwtSigningMethod = "ES384"
	ES512 JwtSigningMethod = "ES512"
	PS256 JwtSigningMethod = "PS256"
	PS384 JwtSigningMethod = "PS384"
	PS512 JwtSigningMethod = "PS512"
)

func GetJwtSigningMethod(signingMethod string) (methodInstance jwt.SigningMethod, err error) {
	switch signingMethod {
	case HS256:
		methodInstance = jwt.SigningMethodHS256
	case HS384:
		methodInstance = jwt.SigningMethodHS384
	case HS512:
		methodInstance = jwt.SigningMethodHS512
	case RS256:
		methodInstance = jwt.SigningMethodRS256
	case RS384:
		methodInstance = jwt.SigningMethodRS384
	case RS512:
		methodInstance = jwt.SigningMethodRS512
	case ES256:
		methodInstance = jwt.SigningMethodES256
	case ES384:
		methodInstance = jwt.SigningMethodES384
	case ES512:
		methodInstance = jwt.SigningMethodES512
	case PS256:
		methodInstance = jwt.SigningMethodPS256
	case PS384:
		methodInstance = jwt.SigningMethodPS384
	case PS512:
		methodInstance = jwt.SigningMethodPS512
	default:
		err = fmt.Errorf("error signing token:%v", err)
	}
	return methodInstance, err
}

func CreateJwt(userId string) (jwtToken string, err error) {
	jwtConfig := common.SrfDirectorGlobalConfig.SrfDirectorJwtConfig
	signingInstance, err := GetJwtSigningMethod(jwtConfig.SrfJwtSigningMethod)
	if err != nil {
		err = fmt.Errorf("error GetJwtSigningMethod: %v", err)
		return
	}
	var secretKey = []byte(jwtConfig.SrfDirectorJwtSecretKey)
	expTime := time.Duration(jwtConfig.SrfDirectorJwtExp)
	claims := jwt.MapClaims{
		"userid": userId,
		"exp":    time.Now().Add(time.Second * expTime).Unix(),
	}
	token := jwt.NewWithClaims(signingInstance, claims)
	jwtToken, err = token.SignedString(secretKey)
	if err != nil {
		return "", fmt.Errorf("error SignedString token: %v", err)
	}
	prefix := "Bearer "
	if jwtConfig.SrfJwtValPrefix != "" {
		prefix = jwtConfig.SrfJwtValPrefix
	}
	jwtToken += prefix
	return
}

func ParseJwt(jwtToken string) (userid string, err error) {
	jwtConfig := common.SrfDirectorGlobalConfig.SrfDirectorJwtConfig
	secretKey := []byte(jwtConfig.SrfDirectorJwtSecretKey)
	signingInstance, err := GetJwtSigningMethod(jwtConfig.SrfJwtSigningMethod)
	if err != nil {
		err = fmt.Errorf("error GetJwtSigningMethod: %v", err)
		return
	}
	token, err := jwt.Parse(jwtToken, func(token *jwt.Token) (interface{}, error) {
		if signingInstance != token.Method {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return secretKey, nil
	})
	if err != nil {
		err = fmt.Errorf("error parsing token: %v", err)
		return
	}
	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return claims["userid"].(string), nil
	}
	err = fmt.Errorf("token is invalid: %v", jwtToken)
	return
}
